import { AudioManager } from "@/utils/AudioManager";

interface RecordingSuccessInfo {
  fullFilePath: string;
  filterFilePath: string;
}

interface RecorderCallbacks {
  onStart?: (() => void);
  onStop?: (() => void);
  onCancel?: (() => void);
  onSuccess?: (res: RecordingSuccessInfo) => void;
  onFail?: (errorMsg: string) => void;
  onComplete?: (() => void);
}

const RECORD_LIMIT_TIME = 60;

export class Recorder {
  isRecording: boolean = false;
  filterInt16Arrays: Int16Array[] = [];
  fullInt16Arrays: Int16Array[] = [];
  isStop: boolean = false;
  isCancel: boolean = false;
  recordTime: number = 0;
  recordTimer: number = 0;
  callbacks?: RecorderCallbacks;


  stop() {
    this.isStop = true;
    clearInterval(this.recordTimer);
    uni.$emit("is-audio-play", { isAudioStop: false });
    uni.getRecorderManager().stop();
  }

  cancel(callback: (() => void)) {
    if (this.isRecording) {
      this.callbacks = {
        onComplete: callback
      }
      this.isCancel = true;
      clearInterval(this.recordTimer);
      uni.$emit("is-audio-play", { isAudioStop: false });
      uni.getRecorderManager().stop();
    } else {
      callback();
    }
  };


  start(info: RecorderCallbacks) {
    /** 录音时，停止播放声音 */
    AudioManager.getInstance().stop();

    /** 如果正在录音，先停止当前录音，并等待回调完成 */
    if (this.isRecording) {
      this.cancel(() => {
        this.start(info);
      })
      uni.getRecorderManager().stop();
      return
    }

    this.callbacks = info;

    /** 清空音频数据 */
    this.filterInt16Arrays.splice(0, this.filterInt16Arrays.length);
    this.fullInt16Arrays.splice(0, this.fullInt16Arrays.length);

    /** 重置各种状态 */
    this.isStop = false;
    this.isCancel = false;
    this.recordTime = 0;
    this.isRecording = true;

    const recorderManager = uni.getRecorderManager();
    const fs = uni.getFileSystemManager();

    recorderManager.onStart(() => {
      console.log("开始录音");
      this.callbacks?.onStart && this.callbacks.onStart()
      this.recordTime = 0;
      this.recordTimer = setInterval(() => {
        this.recordTime += 1;
        if (this.recordTime >= RECORD_LIMIT_TIME) {
          uni.getRecorderManager().stop();
          clearInterval(this.recordTimer)
        }
      }, 1000)
    });


    recorderManager.onStop(() => {
      this.isRecording = false;
      /** 有几种stop的情况， 取消、超时、完成 */
      if (this.isCancel) {
        this.callbacks?.onCancel && this.callbacks.onCancel();
        this.callbacks?.onComplete && this.callbacks?.onComplete();
        return
      }
      if (this.recordTime >= RECORD_LIMIT_TIME) {
        this.callbacks?.onFail && this.callbacks.onFail(`录音时长不得超过${RECORD_LIMIT_TIME}s`)
        this.callbacks?.onComplete && this.callbacks?.onComplete();
        return
      }

      createWavFile(
        mergeInt16Array(this.filterInt16Arrays).buffer,
        `${wx.env.USER_DATA_PATH}/filter.wav`,
        (filterFilePath) => {
          createWavFile(
            mergeInt16Array(this.fullInt16Arrays).buffer,
            `${wx.env.USER_DATA_PATH}/full.wav`,
            (fullFilePath) => {
              this.callbacks?.onSuccess && this.callbacks?.onSuccess({ fullFilePath: fullFilePath, filterFilePath: filterFilePath });
              this.callbacks?.onComplete && this.callbacks?.onComplete();
              clearCallBacks(this.callbacks);
            },
            (errorMsg) => {
              this.callbacks?.onFail && this.callbacks?.onFail(errorMsg);
              this.callbacks?.onComplete && this.callbacks?.onComplete();
              clearCallBacks(this.callbacks);
            }
          );
        },
        (errorMsg) => {
          this.callbacks?.onFail && this.callbacks?.onFail(errorMsg);
          this.callbacks?.onComplete && this.callbacks?.onComplete();
          clearCallBacks(this.callbacks);
        }
      );
    })

    recorderManager.onFrameRecorded((res) => {
      uni.$emit("is-audio-play", { isAudioStop: true });

      let volume = calculateDecibel(res.frameBuffer);
      // console.log(volume);
      let int16Array = new Int16Array(res.frameBuffer);
      this.fullInt16Arrays.push(int16Array);
      if (volume > 60) {
        this.filterInt16Arrays.push(int16Array);
      } else {
        console.log("静音");
      }
    });

    recorderManager.onError((res) => {
      this.isRecording = false;
      this.callbacks?.onFail && this.callbacks?.onFail(res.errMsg);
      this.callbacks?.onComplete && this.callbacks?.onComplete()
      clearCallBacks(this.callbacks)
    });

    recorderManager.start({ sampleRate: 16000, numberOfChannels: 1, format: "pcm", frameSize: 4 });


    function clearCallBacks(info?: RecorderCallbacks) {
      if (info) {
        info.onSuccess = undefined;
        info.onFail = undefined;
        info.onStart = undefined;
        info.onComplete = undefined;
        info.onCancel = undefined;
      }
      uni.$emit("is-audio-play", { isAudioStop: false });
    }

    function calculateDecibel(audioData: ArrayBuffer) {
      // 将16位PCM音频数据解析为Int16Array
      let uint16Array = new Int16Array(audioData);
      let len = uint16Array.length;
      let squareSum = 0; // 平方和
      uint16Array.forEach((uint16) => {
        squareSum += uint16 * uint16;
      });
      // if (squareSum < 10000) return
      let recordVolume = squareSum / len;
      // 计算分贝
      let db = 10 * Math.log10(recordVolume);
      return db;
    }

    function mergeInt16Array(int16Arrays: Int16Array[]) {
      var sumLength = 0;
      for (const i in int16Arrays) {
        sumLength += int16Arrays[i].length;
      }
      const newInt16Array = new Int16Array(sumLength);
      var index = 0;
      for (const i in int16Arrays) {
        for (const j in int16Arrays[i]) {
          newInt16Array[index] = int16Arrays[i][j];
          index++;
        }
      }
      return newInt16Array;
    }

    function createWavFile(pcmData: ArrayBuffer, targetPath: string, onSuccess: (filePath: string) => void, onFail: (errorMsg: string) => void) {
      const sampleRate = 16000;
      const numChannels = 1;
      const sampleBits = 16;

      const headerSize = 44; // WAV文件头部大小固定为44字节

      const totalBytes = pcmData.byteLength;
      const dataBytes = totalBytes;
      const fileSize = totalBytes + headerSize;

      const buffer = new ArrayBuffer(fileSize);
      const dataView = new DataView(buffer);

      setString(dataView, 0, "RIFF");
      dataView.setUint32(4, fileSize, true);
      setString(dataView, 8, "WAVE");
      setString(dataView, 12, "fmt ");
      dataView.setUint32(16, 16, true); // WAVE文件格式块大小为16字节
      dataView.setUint16(20, 1, true); // 编码格式为PCM
      dataView.setUint16(22, numChannels, true); // 声道数
      dataView.setUint32(24, sampleRate, true); // 采样率
      dataView.setUint32(28, (sampleRate * numChannels * sampleBits) / 8, true); // 数据速率
      dataView.setUint16(32, (numChannels * sampleBits) / 8, true); // 每个样本的大小
      dataView.setUint16(34, sampleBits, true); // 位深度
      setString(dataView, 36, "data");
      dataView.setUint32(40, dataBytes, true);

      // 将PCM数据复制到buffer的后面
      const pcmDataView = new DataView(pcmData);
      for (let i = 0; i < dataBytes; ++i) {
        dataView.setUint8(i + headerSize, pcmDataView.getUint8(i));
      }

      fs.writeFile({
        // filePath: `${wx.env.USER_DATA_PATH}/hello.wav`,
        filePath: targetPath,
        data: buffer,
        success(res) {
          onSuccess(targetPath);
        },
        fail(err) {
          onFail(err.errMsg);
        },
      });

      // 设置字符串
      function setString(dataView: DataView, offset: number, value: string) {
        for (let i = 0; i < value.length; i++) {
          dataView.setUint8(offset + i, value.charCodeAt(i));
        }
      }
    }
  }
}
